#pragma once

#include "ColligereDatabaseInterfaceBase.hpp"
#include "ColligereXmlUtils.hpp"

namespace col {

////////////////////////////////////////////
// ColligereDataImporterError
////////////////////////////////////////////

class DataImporterError : public std::exception
{
public:
	DataImporterError() { }
	DataImporterError ( const wxURI &rUri, 
		const wxString &rErrMsg ) : mUri ( rUri ), mErrMsg ( rErrMsg ) { }

	virtual ~DataImporterError() { }

	const char *what() const
	{
		static wxString msg;
		msg.clear();

		if ( mErrMsg.empty() ) return msg.c_str();

		if ( mUri.GetScheme() == "file" )
		{
			msg = boost::str ( boost::format ( _("An error occurred "\
				"while importing: %1%\n\nFile: %2%") ) % mErrMsg % 
				wxURI ( mUri.GetPath() ).BuildUnescapedURI() );
		}
		else
		{
			msg = boost::str ( boost::format ( _("An error occurred "\
				"while importing: %1%\n\nAddress: %2%") ) % mErrMsg % 
				mUri.BuildURI() );
		}

		return msg.c_str();
	}
private:
	const wxString mErrMsg;
	const wxURI mUri;
};

////////////////////////////////////////////
// ColligereDataImporterBase
////////////////////////////////////////////

class DataImporterBase
{
public:
	virtual ~DataImporterBase() { }
	virtual void Load ( const wxURI &rIn ) = 0;
	virtual void Import ( DatabaseInterfaceBase &rDest ) = 0;
	virtual wxUint32 GetItemCount() const = 0;
};

////////////////////////////////////////////
// ColligereXmlDataImporterBase
////////////////////////////////////////////

class XmlDataImporterBase : public DataImporterBase, public XmlUtils
{
protected:
	virtual void InitializeItemFromNode ( const wxXmlNode *pNode, 
		DatabaseItemBase &rItem ) const = 0;
};

////////////////////////////////////////////
// ColligereDataImporterEvent
////////////////////////////////////////////

class DataImporterEvent : public wxEvent
{
public:
	DataImporterEvent ( wxEventType commandType, const DataImporterBase *pImporter,
		const DatabaseItemBase *pItem = 0 )  : wxEvent ( wxID_ANY, commandType ), 
		mpImporter ( pImporter ), mpItem ( pItem ) 
	{
		m_propagationLevel = wxEVENT_PROPAGATE_MAX;
	}

	wxEvent *Clone() const { return ( new DataImporterEvent ( *this ) ); }

	const DataImporterBase *GetImporter() const { return mpImporter; }
	const DatabaseItemBase *GetItem() const { return mpItem; }
private:
	const DataImporterBase *mpImporter;
	const DatabaseItemBase *mpItem;
};

typedef void ( wxEvtHandler::*DataImporterEventFunction )( DataImporterEvent & );

}

#define ColligereDataImporterEventHandlerFunction (wxObjectEventFunction) \
	( wxEventFunction )( col::DataImporterEventFunction )

DECLARE_EVENT_TYPE ( COLLIGERE_EVT_IMPORT_START, -1 )
DECLARE_EVENT_TYPE ( COLLIGERE_EVT_IMPORT_END, -1 )
DECLARE_EVENT_TYPE ( COLLIGERE_EVT_ITEM_IMPORTED, -1 )

#define EVT_IMPORT_START (id, fn) DECLARE_EVENT_TABLE_ENTRY( \
        COLLIGERE_EVT_IMPORT_START, id, -1, \
		ColligereDataImporterEventFunction & fn, \
        ( wxObject * ) NULL ), 

#define EVT_IMPORT_END (id, fn) DECLARE_EVENT_TABLE_ENTRY( \
        COLLIGERE_EVT_IMPORT_END, id, -1, \
		ColligereDataImporterEventFunction & fn, \
        ( wxObject * ) NULL ), 

#define EVT_ITEM_IMPORTED (id, fn) DECLARE_EVENT_TABLE_ENTRY( \
        COLLIGERE_EVT_ITEM_IMPORTED, id, -1, \
		ColligereDataImporterEventFunction & fn, \
        ( wxObject * ) NULL ), 